﻿namespace Digitalmes.Application.Mes;

/// <summary>
/// 工艺查询
/// </summary>
public sealed class ProcessQueryService : IApplicationService
{
    private readonly ConcurrentDictionary<string, ProcRouting> _routingMap = new();

    private readonly SugarRepository<ProcRouting> _routingRepo;

    public ProcessQueryService(SugarRepository<ProcRouting> routingRepo)
    {
        _routingRepo = routingRepo;
    }

    /// <summary>
    /// 获取指定工序的工艺路线明细项。没有找到返回 null。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns></returns>
    public async Task<ProcRoutingItem?> GetRoutingItemAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return null;
        }

        return routing.RoutingItems.FirstOrDefault(s => s.ProcCode == procCode && !s.IsDisabled);
    }

    /// <summary>
    /// 获取指定工序的工艺路线明细项。没有找到返回 null。
    /// </summary>
    /// <remarks>若工艺路线中工位存在回路，通过工位检验会不准确。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns></returns>
    public async Task<ProcRoutingItem?> GetRoutingItem2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return null;
        }

        return routing.RoutingItems
            .Where(s => !s.IsDisabled)
            .OrderBy(s => s.Pos)
            .FirstOrDefault(s => s.Process.OpCodes.Contains(opCode));
    }

    /// <summary>
    /// 获取指定工位的工艺路线明细项。没有找到返回 null。
    /// </summary>
    /// <remarks>从指定的前一工序开始往后查找，当前工位与前一工序可以相同。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="prevProcCode">前一工序编号，若前一工序没找到，返回 null</param>
    /// <param name="opCode">工位号</param>
    /// <returns></returns>
    public async Task<ProcRoutingItem?> GetRoutingItemAsync(string routingCode, string prevProcCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return null;
        }

        var prevProc = routing.RoutingItems.FirstOrDefault(s => s.ProcCode == prevProcCode);
        if (prevProc == null)
        {
            return null;
        }

        return routing.RoutingItems
            .Where(s => s.Pos >= prevProc.Pos && !s.IsDisabled)
            .OrderBy(s => s.Pos)
            .FirstOrDefault(s => s.Process.OpCodes.Contains(opCode));
    }

    /// <summary>
    /// 获取指定工艺路线的首站信息。没有找到返回 null。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <returns></returns>
    public async Task<ProcRoutingItem?> GetFirstRoutingItemAsync(string routingCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return null;
        }

        var proc = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .FirstOrDefault(s => !s.IsDisabled);
        return proc;
    }

    /// <summary>
    /// 检查该工序在该工艺路线中是否存在。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns></returns>
    public async Task<bool> IsExistsAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        return routing.RoutingItems.Any(s => s.ProcCode == procCode);
    }

    /// <summary>
    /// 检查该工位在该工艺路线中是否存在。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns></returns>
    public async Task<bool> IsExists2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        foreach (var item in routing.RoutingItems)
        {
            if (item.Process.OpCodes.Contains(opCode))
            {
                return true;
            }
        }

        return true;
    }

    /// <summary>
    /// 校验当前工序是否为首序。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns></returns>
    public async Task<bool> IsFirstAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        var proc = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .FirstOrDefault(s => !s.IsDisabled)?.Process;
        return proc?.ProcCode == procCode;
    }

    /// <summary>
    /// 校验当前工位是否为首站。
    /// </summary>
    /// <remarks>若工艺路线中工位存在回路，通过工位检验会不准确。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns></returns>
    public async Task<bool> IsFirst2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        var proc = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .FirstOrDefault(s => !s.IsDisabled)?.Process;
        if (proc == null)
        {
            return false;
        }

        return proc.OpCodes.Contains(opCode);
    }

    /// <summary>
    /// 校验当前工序是否为尾序。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns></returns>
    public async Task<bool> IsFinalAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        var proc = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .LastOrDefault(s => !s.IsDisabled)?.Process;
        return proc?.ProcCode == procCode;
    }

    /// <summary>
    /// 校验当前工位是否为末站。
    /// </summary>
    /// <remarks>若工艺路线中工位存在回路，通过工位检验会不准确。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns></returns>
    public async Task<bool> IsFinal2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return false;
        }

        var proc = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .LastOrDefault(s => !s.IsDisabled)?.Process;
        if (proc == null)
        {
            return false;
        }

        return proc.OpCodes.Contains(opCode);
    }

    /// <summary>
    /// 获取此工序的前一工序管控信息，若当前工序为首序，或是没找到，则返回 null。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns>
    /// exist => 当前工序是否有在指定的工艺路线中设置；
    /// procCtl => 查找到的工序管控信息，若当前工序是首站，返回 null。
    /// </returns>
    public async Task<(bool exist, ProcRoutingItem? procCtl)> PrevProcessCtlAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return (false, default);
        }

        var procItems = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .Where(s => !s.IsDisabled)
            .ToArray();
        for (var i = 0; i < procItems.Length; i++)
        {
            if (procItems[i].ProcCode == procCode)
            {
                return (true, i > 0 ? procItems[i - 1] : default);
            }
        }

        return (false, default);
    }

    /// <summary>
    /// 获取此工序的前一工序信息，若当前工序为首序，或是没找到，则返回 null。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns>
    /// exist => 当前工序是否有在指定的工艺路线中设置；
    /// proc => 查找到的工序，若当前工序是首站，返回 null。
    /// </returns>
    public async Task<(bool exist, ProcProcess? proc)> PrevProcessAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return (false, default);
        }

        var procs = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .Where(s => !s.IsDisabled)
            .Select(s => s.Process)
            .ToArray();
        for (var i = 0; i < procs.Length; i++)
        {
            if (procs[i].ProcCode == procCode)
            {
                return  (true, i > 0 ? procs[i - 1] : default);
            }
        }

        return (false, default);
    }

    /// <summary>
    /// 获取此工位的前一工序信息，若当前工位为首序，或是没找到，则返回 null。
    /// </summary>
    /// <remarks>若工艺路线中工位存在回路，通过工位检验会不准确。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns>
    /// exist => 当前工位是否有在指定的工艺路线中设置；
    /// proc => 查找到的工序，若当前工位是首站，返回 null。
    /// </returns>
    public async Task<(bool exist, ProcProcess? proc)> PrevProcess2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return (false, default);
        }

        var procs = routing.RoutingItems
            .OrderBy(s => s.Pos)
            .Where(s => !s.IsDisabled)
            .Select(s => s.Process).ToArray();
        for (var i = 0; i < procs.Length; i++)
        {
            if (procs[i].OpCodes.Contains(opCode))
            {
                return (true, i > 0 ? procs[i - 1] : default);
            }
        }

        return (false, default);
    }

    /// <summary>
    /// 获取此工序的后一工序信息。没有找到返回 null。
    /// </summary>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="procCode">工序编号</param>
    /// <returns>
    /// exist => 当前工序是否有在指定的工艺路线中设置；
    /// proc => 查找到的工序，若当前工序是尾站，返回 null。
    /// </returns>
    public async Task<(bool exist, ProcProcess? proc)> NextProcessAsync(string routingCode, string procCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return (false, default);
        }

        var procs = routing.RoutingItems
            .OrderByDescending(s => s.Pos)
            .Where(s => !s.IsDisabled)
            .Select(s => s.Process)
            .ToArray();
        for (var i = 0; i < procs.Length; i++)
        {
            if (procs[i].ProcCode == procCode)
            {
                return (true, i > 0 ? procs[i - 1] : default);
            }
        }

        return (false, default);
    }

    /// <summary>
    /// 获取此工位的后一工序信息。没有找到返回 null。
    /// </summary>
    /// <remarks>若工艺路线中工位存在回路，通过工位检验会不准确。</remarks>
    /// <param name="routingCode">工业路线编号</param>
    /// <param name="opCode">工位编号</param>
    /// <returns>
    /// exist => 当前工位是否有在指定的工艺路线中设置；
    /// proc => 查找到的工序，若当前工位是尾站，返回 null。
    /// </returns>
    public async Task<(bool exist, ProcProcess? proc)> NextProcess2Async(string routingCode, string opCode)
    {
        var routing = await GetRoutingAsync(routingCode);
        if (routing == null)
        {
            return (false, default);
        }

        var procs = routing.RoutingItems
            .OrderByDescending(s => s.Pos)
            .Where(s => !s.IsDisabled)
            .Select(s => s.Process).ToArray();
        for (var i = 0; i < procs.Length; i++)
        {
            if (procs[i].OpCodes.Contains(opCode))
            {
                return (true, i > 0 ? procs[i - 1] : default);
            }
        }

        return (false, default);
    }

    /// <summary>
    /// 查询工艺路线，没有找到则返回 null。
    /// </summary>
    /// <param name="routingCode"></param>
    /// <returns></returns>
    private async Task<ProcRouting> GetRoutingAsync(string routingCode)
    {
        await Task.CompletedTask;

        return _routingMap.GetOrAdd(routingCode, _ => _routingRepo.AsQueryable()
           .Includes(s => s.RoutingItems, t => t.Process)
           .First(s => s.RoutingCode == routingCode));
    }
}
